﻿//*** Guidance generated code ***//
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.Linq;
using System.Web.Profile;

using ProjectBase.Core;
using ProjectBase.Core.Service;
using $safeprojectname$.Business.Services;
using $safeprojectname$.Data.Services;
using $prjsn$.Entity.Services;

namespace $safeprojectname$.Providers
{
    public class ProjectProfileProvider : ProfileProvider
    {
        public override void Initialize(string name, NameValueCollection config)
        {
            // Provider name
            name = name.IsNotEmpty() ? name : "ProjectProfileProvider";

            ApplicationName = config["applicationName"];

            // Application name
            if (ApplicationName.IsEmpty())
            {
                ApplicationName = System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath;
                config["applicationName"] = ApplicationName;
            }

            // create facade
            Facade = Factory.CreateInstance<IUserProfileFacade>();

            // create dao
            var connectionStringName = config["connectionStringName"];
            if (connectionStringName.IsEmpty())
            {
                throw new ConfigurationErrorsException("Cannot find attribute 'connectionStringName' in .config file, element system.web/profile/providers/add[name=ProjectProfile]");

            }
            var dao = Factory.CreateInstance<IUserProfileDao>();
            dao.ConnectionStringName = connectionStringName;

            // DI, inject Dao into Facade
            Facade.Dao = dao;

            // init base
            base.Initialize(name, config);
        }

        #region Delete
        public override int DeleteInactiveProfiles(ProfileAuthenticationOption authenticationOption,
            DateTime userInactiveSinceDate)
        {
            bool? isAnonymous =
                authenticationOption.Equals(ProfileAuthenticationOption.Authenticated)
                ? false
                : authenticationOption.Equals(ProfileAuthenticationOption.Anonymous)
                    ? true as bool?
                    : null;

            var filter = new UserProfileFilter
            {
                IsAnonymous = isAnonymous,
                LastActivityDateTo = userInactiveSinceDate.AddMinutes(+5),
            };

            return Delete(filter);
        }

        public override int DeleteProfiles(string[] usernames)
        {
            var filter = new UserProfileFilter();
            var result = 0;

            foreach (var username in usernames)
            {
                filter.UserName = username;
                result += Delete(filter);
            }
            return result;
        }

        public override int DeleteProfiles(ProfileInfoCollection profiles)
        {
            var filter = new UserProfileFilter();
            var result = 0;

            foreach (ProfileInfo profile in profiles)
            {
                filter.UserName = profile.UserName;
                result += Delete(filter);
            }
            return result;
        }
        protected virtual int Delete(UserProfileFilter filter)
        {
            var list = Facade.Find(filter).ToList();
            foreach (var userProfile in list)
            {
                var entity = userProfile;
                Facade.Delete(entity);
            }
            return filter.TotalRows;
        }
        #endregion Delete

        #region ProfileInfoCollection
        public override ProfileInfoCollection FindInactiveProfilesByUserName(
            ProfileAuthenticationOption authenticationOption,
            string usernameToMatch,
            DateTime userInactiveSinceDate,
            int pageIndex,
            int pageSize,
            out int totalRecords)
        {
            bool? isAnonymous =
                authenticationOption.Equals(ProfileAuthenticationOption.Authenticated)
                ? false
                : authenticationOption.Equals(ProfileAuthenticationOption.Anonymous)
                    ? true as bool?
                    : null;

            var filter = new UserProfileFilter
            {
                UserName = usernameToMatch,
                CurrentPage = pageIndex,
                TakeRows = pageIndex,
                IsAnonymous = isAnonymous,
                LastActivityDateTo = userInactiveSinceDate.AddMinutes(+5),
            };
            var list = Facade.Find(filter);
            totalRecords = filter.TotalRows;

            return AsProfileInfoColl(list);
        }

        public override ProfileInfoCollection FindProfilesByUserName(
            ProfileAuthenticationOption authenticationOption,
            string usernameToMatch,
            int pageIndex,
            int pageSize,
            out int totalRecords)
        {
            bool? isAnonymous =
                authenticationOption.Equals(ProfileAuthenticationOption.Authenticated)
                ? false
                : authenticationOption.Equals(ProfileAuthenticationOption.Anonymous)
                    ? true as bool?
                    : null;

            var filter = new UserProfileFilter
            {
                UserName = usernameToMatch,
                CurrentPage = pageIndex,
                TakeRows = pageIndex,
                IsAnonymous = isAnonymous,
            };
            var list = Facade.Find(filter);
            totalRecords = filter.TotalRows;

            return AsProfileInfoColl(list);
        }

        public override ProfileInfoCollection GetAllInactiveProfiles(
            ProfileAuthenticationOption authenticationOption,
            DateTime userInactiveSinceDate,
            int pageIndex,
            int pageSize,
            out int totalRecords)
        {
            bool? isAnonymous =
                authenticationOption.Equals(ProfileAuthenticationOption.Authenticated)
               ? false
               : authenticationOption.Equals(ProfileAuthenticationOption.Anonymous)
                   ? true as bool?
                   : null;

            var filter = new UserProfileFilter
            {
                CurrentPage = pageIndex,
                TakeRows = pageIndex,
                IsAnonymous = isAnonymous,
                LastActivityDateTo = userInactiveSinceDate.AddMinutes(+5)
            };
            var list = Facade.Find(filter);
            totalRecords = filter.TotalRows;

            return AsProfileInfoColl(list);
        }

        public override ProfileInfoCollection GetAllProfiles(
            ProfileAuthenticationOption authenticationOption,
            int pageIndex,
            int pageSize,
            out int totalRecords)
        {
            bool? isAnonymous =
                authenticationOption.Equals(ProfileAuthenticationOption.Authenticated)
                ? false
                : authenticationOption.Equals(ProfileAuthenticationOption.Anonymous)
                    ? true as bool?
                    : null;

            var filter = new UserProfileFilter
            {
                CurrentPage = pageIndex,
                TakeRows = pageIndex,
                IsAnonymous = isAnonymous,
            };
            var list = Facade.Find(filter);
            totalRecords = filter.TotalRows;

            return AsProfileInfoColl(list);
        }

        public override int GetNumberOfInactiveProfiles(
            ProfileAuthenticationOption authenticationOption,
            DateTime userInactiveSinceDate)
        {
            var filter = new UserProfileFilter
            {
                TakeRows = 1,
                LastActivityDateTo = userInactiveSinceDate.AddMinutes(5),
            };
            Facade.Find(filter);
            return filter.TotalRows;
        }
        #endregion ProfileInfoCollection

        #region Profile protected

        protected ProfileInfo AsProfileInfo(UserProfile profile)
        {
            return new ProfileInfo(profile.UserName,
                profile.IsAnonymous,
                profile.LastActivityDate,
                profile.LastUpdateDate,
                profile.SerializedSession.Count);
        }
        protected ProfileInfoCollection AsProfileInfoColl(IEnumerable<UserProfile> userProfiles)
        {
            var coll = new ProfileInfoCollection();
            if (userProfiles.IsEmpty())
            {
                return coll;
            }
            foreach (var userProfile in userProfiles)
            {
                coll.Add(AsProfileInfo(userProfile));
            }
            return coll;
        }
        #endregion Profile protected

        #region Get / Set PropertyValue
        public override SettingsPropertyValueCollection GetPropertyValues(
            SettingsContext context,
            SettingsPropertyCollection collection)
        {
            // clear previous issues track
            Facade.Messages.Clear();
            var userName = (string)context["UserName"];
            var isAnonymous = !(bool)context["IsAuthenticated"];

            // I. UserProfile
            UserProfile userProfile;
            if (userName.IsNotEmpty())
            {
                // load or create new profile
                userProfile = Facade.GetOrCreateUserProfile(userName, isAnonymous, ApplicationName);

                // remember the bytes, representing last session
                userProfile.LastBytes = ProjectBase.Core.Ext.ToByteArray(userProfile.SerializedSession);
            }
            else
            {
                // anonymous user
                userProfile = new UserProfile
                {
                    SerializedSession = new Dictionary<string, object>()
                };
            }

            // II. Profile
            var settings = new SettingsPropertyValueCollection();

            foreach (SettingsProperty property in collection)
            {
                var value = new SettingsPropertyValue(property);
                settings.Add(value);
                switch (property.Name)
                {
                    case "Session":
                        value.PropertyValue = userProfile.SerializedSession;
                        break;
                    case "UserProfile":
                        value.PropertyValue = userProfile;
                        break;
                }
            }

            return settings;
        }
        public override void SetPropertyValues(
            SettingsContext context,
            SettingsPropertyValueCollection collection)
        {
            var userName = (string)context["UserName"];
            //var isAnonymous = !(bool)context["IsAuthenticated"];

            // no need to continue, to persist for anonymous
            if (userName.IsEmpty())
            {
                return;
            }

            foreach (SettingsPropertyValue value in collection)
            {
                if (value.Name.IsEqual("UserProfile"))
                {
                    var userProfile = value.PropertyValue as UserProfile;
                    if (userProfile.Is())
                    {
                        // compare serialized session
                        var currentBytes = ProjectBase.Core.Ext.ToByteArray(userProfile.SerializedSession);
                        var isDirty = !userProfile.LastBytes.Compare(currentBytes);

                        // session is changed
                        if (isDirty)
                        {
                            userProfile.LastUpdateDate = DateTime.Now;
                            userProfile.LastActivityDate = userProfile.LastUpdateDate;
                            Facade.Update(userProfile);
                        }
                        // only update ActivityDate
                        else if (userProfile.LastActivityDate <= DateTime.Now.AddMinutes(-5))
                        {
                            userProfile.LastActivityDate = DateTime.Now;
                            Facade.Update(userProfile);
                        }
                    }
                }
            }
        }
        #endregion Get / Set PropertyValue

        #region properties
        public override string ApplicationName { get; set; }
        public virtual IUserProfileFacade Facade { protected get; set; }
        #endregion properties
    }
}
